import * as THREE from "three"
import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

let renderer, camera, scene, controls, stats

{
    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setAnimationLoop(animate)
    document.body.appendChild(renderer.domElement);

    //
    stats = new Stats();
    document.body.appendChild(stats.dom);

    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 50);
    camera.position.z = 4;

    controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;

    scene = new THREE.Scene();


}

// scene
{

    const geometry = new THREE.TorusKnotGeometry(1, 0.3, 128, 64)
    const material = new THREE.MeshBasicMaterial({ color: 0x0000ff })

    const count = 50
    const scale = 5

    for (let i = 0; i < count; i++) {

        const r = Math.random() * 2.0 * Math.PI;
        const z = (Math.random() * 2.0) - 1.0;
        const zScale = Math.sqrt(1.0 - z * z) * scale;

        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.set(
            Math.cos(r) * zScale,
            Math.sin(r) * zScale,
            z * scale
        );
        mesh.rotation.set(Math.random(), Math.random(), Math.random());
        scene.add(mesh);

    }
}

let target
let postScene, postCamera, postMaterial

const params = {
    format: THREE.DepthFormat,
    type: THREE.UnsignedShortType
}



setupRenderTarget();

// post 
{
    const vertexShader = `
        varying vec2 vUv;

        void main(){
            vUv=uv;
            gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.);
        }`

    const fragmentShader = `
        #include <packing>

        varying vec2 vUv;
        uniform sampler2D tDiffuse;
        uniform sampler2D tDepth;
        uniform float cameraNear;
        uniform float cameraFar;

        float readDepth(sampler2D depthSampler,vec2 coord){
            float fragCoordZ=texture2D(depthSampler,coord).x;
            float viewZ=perspectiveDepthToViewZ(fragCoordZ,cameraNear,cameraFar);
            return viewZToOrthographicDepth(viewZ,cameraNear,cameraFar);
        }

        void main(){
            float depth=readDepth(tDepth,vUv);
            gl_FragColor.rgb=1.-vec3(depth);
            gl_FragColor.a=1.;
        }
        `
    // Setup post processing stage
    postCamera = new THREE.OrthographicCamera(- 1, 1, 1, - 1, 0, 1);

    postMaterial = new THREE.ShaderMaterial({
        vertexShader,
        fragmentShader,
        uniforms: {
            cameraNear: { value: camera.near },
            cameraFar: { value: camera.far },
            tDiffuse: { value: null },
            tDepth: { value: null }
        }
    });
    const postPlane = new THREE.PlaneGeometry(2, 2);
    const postQuad = new THREE.Mesh(postPlane, postMaterial);
    postScene = new THREE.Scene();
    postScene.add(postQuad);

}

// onWindowResize();
// window.addEventListener( 'resize', onWindowResize );

// //
// const gui = new GUI( { width: 300 } );

// gui.add( params, 'format', formats ).onChange( setupRenderTarget );
// gui.add( params, 'type', types ).onChange( setupRenderTarget );
// gui.open();


function setupRenderTarget() {

    if (target) target.dispose()

    const format = parseFloat(params.format)
    const type = parseFloat(params.type)

    target = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight)
    target.texture.minFilter = target.texture.magFilter = THREE.NearestFilter
    target.stencilBuffer = format === THREE.DepthStencilFormat
    target.depthTexture = new THREE.DepthTexture()
    target.depthTexture.format = format
    target.depthTexture.type = type

}

const plane = new THREE.Mesh(new THREE.PlaneGeometry(0.3, 0.3), new THREE.ShaderMaterial(
    {
        vertexShader: `
        varying vec2 vUv;

        void main(){
            vUv=uv;
            gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.);
        }`,
        fragmentShader: `

        varying vec2 vUv;
        uniform sampler2D tTexture;

        void main(){
            vec3 color=texture2D(tTexture,vUv).xyz;
            gl_FragColor.rgb=color;
            gl_FragColor.a = 1.;
        }
        `,
        uniforms: {
            tTexture: {
                value: null
            }
        }
    }
))

postScene.add(plane)

function animate() {

    // 给当前场景拍个照
    renderer.setRenderTarget(target)
    renderer.render(scene, camera)
    renderer.setRenderTarget(null);

    plane && (plane.material.uniforms.tTexture.value = target.texture)
    // render post FX
    postMaterial.uniforms.tDiffuse.value = target.texture;
    postMaterial.uniforms.tDepth.value = target.depthTexture;
    renderer.render(postScene, postCamera)
    // renderer.render(scene, camera)


    stats.update()
}

function onWindowResize() {

    const aspect = window.innerWidth / window.innerHeight;
    camera.aspect = aspect;
    camera.updateProjectionMatrix();

    const dpr = renderer.getPixelRatio();
    target.setSize(window.innerWidth * dpr, window.innerHeight * dpr);
    renderer.setSize(window.innerWidth, window.innerHeight);

}

onWindowResize();
window.addEventListener('resize', onWindowResize);